package cn.android666.ping

import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.os.Message
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import cn.android666.ping.databinding.ActivityMainBinding
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.Subscribe
import org.greenrobot.eventbus.ThreadMode
import java.io.BufferedReader
import kotlin.concurrent.thread

class MainActivity : AppCompatActivity() {

    private lateinit var binding: ActivityMainBinding
    private lateinit var mAdapter: MyAdapter
    private val lines = ArrayList<String>()
    private var pingProcess: Process? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        EventBus.getDefault().register(this)
        supportActionBar?.hide()
        binding = ActivityMainBinding.inflate(layoutInflater)
        setContentView(binding.root)

        mAdapter = MyAdapter()
        binding.recyclerView.layoutManager = LinearLayoutManager(this)
        binding.recyclerView.adapter = mAdapter
        binding.startPingButton.setOnClickListener { startPing() }
        binding.stopPingButton.setOnClickListener { stopPing() }
        binding.settingsButton.setOnClickListener { startActivity(Intent(this, SettingsActivity::class.java)) }
        checkPingCommand()
    }

    override fun onDestroy() {
        super.onDestroy()
        EventBus.getDefault().unregister(this)
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    fun onEvent(msg: Message) {
        if (msg.what == Whats.REFRESH_COMMAND) {
            checkPingCommand()
        }
    }

    private fun stopPing() {
        try {
            pingProcess?.let { sendSigInt(it) } // 发送 SIGINT（signal=2），这种方式可以得到ping的统计结果
        } catch (e: Exception) {
            e.printStackTrace()
            // 反射失败时回退到普通 destroy()
            pingProcess?.destroy() // 这种方式是发送SIGTERM（signal=15），它不会得到ping的统计结果，且会让ping的地方抛出InterruptedException
        } finally {
            pingProcess = null
        }
    }

    /** 模拟Ctrl + C */
    fun sendSigInt(process: Process) {
        try {
            // 获取进程 PID（需反射或通过 shell）
            val pid = getPid(process) // 见下方 PID 获取方法
            Runtime.getRuntime().exec("kill -2 $pid").waitFor()
        } catch (e: Exception) {
            process.destroy() // 回退到普通终止
        }
    }

    // 获取 PID 的方法（需适配不同 Android 版本）
    private fun getPid(process: Process): Long {
        return try {
            // 方法 1: 反射获取（适用于旧版 Android）
            val pidField = process::class.java.getDeclaredField("pid")
            pidField.isAccessible = true
            println("正常获取pid")
            pidField.getLong(process)
        } catch (e: NoSuchFieldException) {
            println("不正常获取pid")
            // 方法 2: 通过 shell 命令获取（通用但较慢）
            val pidStr = Runtime.getRuntime()
                .exec("ps | grep ${process.javaClass.name} | awk '{print \$2}'")
                .inputStream.bufferedReader().use { it.readLine() }
            pidStr?.toLongOrNull() ?: -1
        }
    }

    private fun checkPingCommand(): Boolean {
        lines.clear()
        val pingCommand = PersistentVariables.pingCommand
        addData("当前命令为：$pingCommand")
        return if (pingCommand.isEmpty()) {
            addData("命令格式错误，请先点击设置按钮进行设置")
            false
        } else {
            true
        }
    }

    private fun startPing() {
        binding.startPingButton.isEnabled = false
        lines.clear()

        if (!checkPingCommand()) {
            return
        }

        addData("正在执行命令...")

        /*val args = PersistentVariables.pingCommand.split(" ")
        thread { startPing(args) }*/

        thread { startPing(PersistentVariables.pingCommand) }
    }

    private fun readData(bufferedReader: BufferedReader?) = thread {
        try {
            bufferedReader?.use { reader ->
                var line: String?
                while (reader.readLine().also { line = it } != null) {
                    val lineTemp = line!!
                    runOnUiThread { addData(lineTemp) } // 这里切换到了UI线程，子线程继续执行时可以已经把line对象又赋值为null了，所以使用了lineTemp来预防值被重新赋值
                }
            }
        } catch (e: Exception) {
            if (e is InterruptedException) {
                println("正常终止了进程")
            } else {
                runOnUiThread { addData("出现异常：${e.javaClass.simpleName}: ${e.message}") }
            }
        }
    }

    private fun startPing(command: String) {
        try {
            pingProcess = Runtime.getRuntime().exec(command)
            val process = pingProcess
            val bufferedReader1 = pingProcess?.inputStream?.bufferedReader()
            val bufferedReader2 = pingProcess?.errorStream?.bufferedReader()
            readData(bufferedReader1)
            readData(bufferedReader2)

            // 这里为什么用一个process局部变量，因为调用停止函数的时候会把全局的pingProcess设置为空。
            val exitCode = process?.waitFor() // 等待进程结束，这是一个阻塞函数，所以可以等待前面的两个读取线程读取结束。
            Log.i("Ping", "exitCode = $exitCode")
            /* if (exitCode != 0) { // 不显示了，要不还得跟客户解释代码的函义
                 runOnUiThread { addData("未正常终止，错误码：$exitCode") }
             }*/
        } catch (e: Exception) {
            if (e is InterruptedException) {
                println("正常终止了进程")
            } else {
                runOnUiThread { addData("出现异常：${e.javaClass.simpleName}: ${e.message}") }
            }
        } finally {
            runOnUiThread {
                binding.startPingButton.isEnabled = true
                addData("命令执行结束。")
            }
        }
    }

    private fun startPing(args: List<String>) {
        try {
            pingProcess = ProcessBuilder()
                .command(args) // 这种方式要求指定命令的路径，如：/system/bin/ping
                .redirectErrorStream(true) // 合并错误输出到标准输出
                .start()

            val process = pingProcess
             process?.inputStream?.bufferedReader()?.use { reader ->
                var line: String?
                while (reader.readLine().also { line = it } != null) {
                    val lineTemp = line!!
                    runOnUiThread { addData(lineTemp) } // 这里切换到了UI线程，子线程继续执行时可以已经把line对象又赋值为null了，所以使用了lineTemp来预防值被重新赋值
                }
            }

            // 这里为什么用一个process局部变量，因为调用停止函数的时候会把全局的pingProcess设置为空。
            val exitCode = process?.waitFor() // 等待进程结束，这是一个阻塞函数。虽然前面读取了完了输入流的内容，但是进程有可能还在运行。
            Log.i("Ping", "exitCode = $exitCode")
            /* if (exitCode != 0) { // 不显示了，要不还得跟客户解释代码的函义
                 runOnUiThread { addData("未正常终止，错误码：$exitCode") }
             }*/
        } catch (e: Exception) {
            if (e is InterruptedException) {
                println("正常终止了进程")
            } else {
                runOnUiThread { addData("出现异常：${e.javaClass.simpleName}: ${e.message}") }
            }
        } finally {
            runOnUiThread {
                binding.startPingButton.isEnabled = true
                addData("命令执行结束。")
            }
        }
    }

    private fun addData(data: String) {
        lines.add(data)
        refreshListView()
    }

    private fun refreshListView() {
        mAdapter.notifyDataSetChanged()
        binding.recyclerView.scrollToPosition(lines.size - 1)
    }

    internal inner class MyViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        var textView: TextView = itemView as TextView
    }

    internal inner class MyAdapter : RecyclerView.Adapter<MyViewHolder>() {

        override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
            return MyViewHolder(TextView(parent.context).apply {
                textSize = 11f
                setTextColor(Color.BLACK)
            })
        }

        override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
            holder.textView.text = lines[position]
        }

        override fun getItemCount(): Int {
            return lines.size
        }
    }
}